<?php

if (!defined('TOBBIVM'))
	header('location:/template/notrepassing.php');
/**
 * This file is part of TobbiVMShop.
 *
 * TobbiVMShop is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * TobbiVMShop is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with TobbiVMShop.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Datei: calculate.class.php
 *
 * Class with all methodes for calculate prices,
 * taxes and create price-/tax-strings with the currency-symbol
 * Used by the cart-systen
 *
 * @author Norbert Gebert
 * @copyright Norbert Gebert 25.09.2015
 * @license GPL3
 *
 * @version 0.5b
 * @package Admin
 * @subpackage global
 */
class calculate
{

	private $_currency = "";
	private $_totalPrice = 0;
	private $_totalPriceTax = array();
	private $_priceUnit = '';
	private $_taxName = '';

	/**
	 * Set the currency-symbol inclusive separator or other
	 * @param string $currency              currency-symbol
	 * @return      none
	 */
	public function setCurrency($currency)
	{
		$this->_currency = $currency;
	}

	/**
	 * Returns the price per item inclusive/without
	 * the currency-symbol
	 * @param string	$productId      product-id
	 * @param string	$count          number of the product
	 * @param bool		$withTax        TRUE = incl. tax, FALSE = without tax
	 * @param bool		$currency       TRUE = incl. currency-symbol, FALSE = without
	 * @return      string with price to display
	 */
	public function productPricePerItem($productId, $count, $cart, $withTax = TRUE, $currency = TRUE)
	{
		$pricex = $this->_stringToFloat(
				$this->productPrice($productId, $count, $cart, $withTax, FALSE)) / $count;
		$priceStr = $this->_floatToString($pricex);

		//if ($currency === TRUE)
		$priceStr .= $this->_currency;

		return $priceStr;
	}

	/**
	 * Returns the price inclusive/without
	 * the currency-symbol
	 * @param string		$productId	product-id
	 * @param string		$count		number of the product
	 * @param bool			$withTax		TRUE = incl. tax, FALSE = without tax
	 * @param bool			$currency	TRUE = incl. currency-symbol, FALSE = without
	 * @return string with price to display
	 */
	public function productPrice($productId, $count, $cart, $withTax = TRUE, $currency = TRUE)
	{
		db::getInstance()->where('product_id', $productId);
		$priceId = db::getInstance()->getOne('product', null, 'product_price_id');

		$cols = array('price_art', 'price_per_item', 'price_fix', 'price_list', 'price_unit');
		db::getInstance()->where('price_id', $priceId['product_price_id']);
		$result = db::getInstance()->getOne('price', null, $cols);

		switch ($result['price_art'])
		{
			case '0': // free
				$this->_priceUnit = _('This article is free!');
				$pricex = 0;
				break;
			case '1': // price per item
				$this->_priceUnit = _('Price per item');
				$pricex = $result['price_per_item'] * $count;
				break;
			case '2': // (price * item ) + fixCosts
				$this->_priceUnit = _('Price per item');
				$pricex = ($result['price_per_item'] * $count) + $result['price_fix'];
				break;
			case '3': // pricelist with graduated prices
				// TODO include user-attributes prices
				$rows = explode("\r\n", $result['price_list']);

				foreach ($rows as $row)
				{
					$values = explode(':', $row);
					$value = explode('-', $values[0]);

					if ($count >= intval($value[0]) and $count <= intval($value[1]))
						$pricex = $count * str_replace(',', '.', $values[1]) +
							$result['price_fix'];
				}
				$this->_priceUnit = _('Price per item');
				break;
		}

		// Update price in $pricex depending on selected options
		$rows = explode(';', $cart['optionsText']);

		foreach ($rows as $row)
		{
			$value = explode('|', $row);

			if (!empty($value[3]))
			{
				$sign = substr($value[3], 0, 1);

				switch ($sign)
				{
					case '+': // add value to price
						$pricex = (($this->_stringToFloat($value[3]) * $count) +
							$this->_stringToFloat($pricex));
						break;
					case '-': // subtract value from price
						$pricex = ($this->_stringToFloat($pricex) +
							($this->_stringToFloat($value[3]) * $count));
						break;
					case '=': // replace price with value
						$pricex = ($this->_stringToFloat(substr($value[3], 1)) * $count);
						break;
				}
			}
		}

		$this->_addTax($pricex, $productId, FALSE);

		if ($withTax = FALSE AND $pricex <> 0)
			$pricex -= $this->_stringToFloat($this->getTax($pricex, $productId, FALSE));

		$priceStr = $this->_floatToString($pricex);

		if ($currency === TRUE)
			$priceStr .= $this->_currency;

		return $priceStr;
	}

	/**
	 * Returns the price-unit from last called pricePerItem()
	 * or productPrice()-call
	 * @param string        $Id     product-id
	 * @return string       with unit-string to display
	 */
	public function getproductUnit()
	{
		return $this->_priceUnit;
	}

	/**
	 * Returns the tax from given price inclusive/without
	 * the currency-symbol
	 * @param string/float  $price     product-price
	 * @param string        $productId product-id
	 * @param bool          $currency  TRUE = incl. currency-symbol, FALSE = without
	 * @return string tax to display
	 */
	public function getTax($price, $productId, $currency = TRUE)
	{
		db::getInstance()->where('product_id', $productId);
		$taxId = db::getInstance()->getOne('product', null, 'product_tax_id');

		$cols = array('tax_value', 'tax_name');
		db::getInstance()->where('tax_id', $taxId['product_tax_id']);
		$result = db::getInstance()->getOne('tax', null, $cols);

		if (db::getInstance()->count >= 1)
		{
			$this->_taxName = $result['tax_name'];
			//$taxx = $this->_stringToFloat($price) / ($result->tax_value / 100);
			$taxx = ($this->_stringToFloat($price) / (100 + $result['tax_value'])) * $result['tax_value'];
		}

		if ($currency === TRUE)
			return $this->_floatToString($taxx) . $this->_currency;

		return $this->_floatToString($taxx);
	}

	/**
	 * Returns the tax-name called getTax()-call
	 * @return string       with tax-name
	 */
	public function getTaxName()
	{
		return $this->_taxName;
	}

	/**
	 * Add price to build the order-total (and clear them)
	 * @param string/float  $price     product-price
	 * @param string/float  $productId product-id
	 * @param bool          $clear     set the price to 0 and add the new price
	 * @return none
	 */
	public function addToTotalPrice($price, $productId, $clear = FALSE)
	{
		if ($clear === TRUE)
		{
			$this->_totalPrice = 0;
			$this->_totalPriceTax = array();
		}

		if (is_string($price))
			$this->_totalPrice += $this->_stringToFloat($price);

		if (is_float($price))
			$this->_totalPrice += $price;

		db::getInstance()->where('product_id', $productId);
		$taxId = db::getInstance()->getOne('product', null, 'product_tax_id');
		$this->_addTax($price, $taxId['product_tax_id']);
	}

	/**
	 * Add special price to build the order-total (and clear them)
	 * @param string/float  $price  tax-price
	 * @param string/float  $taxId  tax-id
	 * @param bool          $clear  set the price to 0 and add the new price
	 * @return none
	 */
	public function addSpecialToTotalPrice($price, $taxId, $clear = FALSE)
	{
		if ($clear === TRUE)
		{
			$this->_totalPrice = 0;
			$this->_totalPriceTax = array();
		}

		if (is_string($price))
			$this->_totalPrice += $this->_stringToFloat($price);

		if (is_float($price))
			$this->_totalPrice += $price;

		$this->_addTax($price, $taxId);
	}

	/**
	 * get total-price inclusive/without
	 * the currency-symbol but incl. tax
	 * @param bool $currency  TRUE = incl. currency-symbol, FALSE = without
	 * @return string total price from addPrice() to display
	 */
	public function getTotalPrice($currency)
	{
		if ($currency === TRUE)
		{
			return $this->_floatToString($this->_totalPrice) . $this->_currency;
		}
		else
		{
			return $this->_floatToString($this->_totalPrice);
		}
	}

	/**
	 * get total-price-tax inclusive/without
	 * the currency-symbol
	 * @param bool  $currency  TRUE = incl. currency-symbol, FALSE = without
	 * @return array total-price-tax build from addPrice() to display
	 */
	public function getTotalPriceTax($currency = TRUE)
	{
		$taxlist = array();
		$curr = '';
		if ($currency === TRUE)
			$curr = $this->_currency;

		if (count($this->_totalPriceTax) >= 1)
		{
			foreach ($this->_totalPriceTax as $value)
			{
				$taxlist[] = array(
				 'name' => $value['name'],
				 'percent' => $value['percent'],
				 'value' => $this->_floatToString($value['value']) . $curr
				);
			}
		}
		return $taxlist;
	}

	/**
	 * Create a price-string to display
	 * @param mixed $price          string or float
	 * @param bool  $currency       TRUE = incl. currency-symbol, FALSE = without
	 * @param int   $decimal        Decimals to round
	 * @return      string
	 */
	public function formatToPrice($price, $currency = TRUE, $decimals = 2)
	{
		if (is_float($price))
		{
			$priceString = $this->_floatToString($price, $decimals);
		}
		else
		{
			$a = $this->_stringToFloat($price);
			$priceString = $this->_floatToString($a, $decimals);
		}

		if ($currency === TRUE)
			$priceString .= $this->_currency;

		return $priceString;
	}

	/**
	 * Add tax from given product to taxbuffer
	 * @param string        $price          product-price
	 * @param string        $productId      product-id
	 * @return string tax to display
	 */
	private function _addTax($price, $taxId)
	{
		$cols = array('tax_value', 'tax_name');
		db::getInstance()->where('tax_id', $taxId);
		$result = db::getInstance()->getOne('tax', null, $cols);

		if (db::getInstance()->count >= 1)
		{
			$taxx = ($this->_stringToFloat($price) / (100 + $result['tax_value'])) * $result['tax_value'];
			$row = 0;
			$found = FALSE;

			if (count($this->_totalPriceTax) == 0)
			{
				$this->_totalPriceTax[] = array(
				 'name' => $result['tax_name'],
				 'percent' => $result['tax_value'],
				 'value' => $taxx);
			}
			else
			{
				foreach ($this->_totalPriceTax as $value)
				{
					if ($value['name'] === $result['tax_name'])
					{
						$found = TRUE;
						break;
					}
					$row++;
				}
				if ($found == TRUE)
				{
					$this->_totalPriceTax[$row]['value'] += $taxx;
				}
				else
				{
					$this->_totalPriceTax[] = array(
					 'name' => $result['tax_name'],
					 'percent' => $result['tax_value'],
					 'value' => $taxx);
				}
			}
		}
		else
		{
			$taxx = 0;
		}
		return $this->_floatToString($taxx);
	}

	/**
	 * string to float with change "," to "."
	 * @param string        $price          product-price
	 * @return float
	 */
	private function _stringToFloat($price)
	{
		$price = preg_replace('[^0-9\,\.\-\+]', '', strval($price));
		$price = strtr($price, ',', '.');
		$pos = strrpos($price, '.');
		return ($pos === false ? floatval($price) :
				floatval(str_replace('.', '', substr($price, 0, $pos)) . substr($price, $pos)));
	}

	/**
	 * float to string with change "." to ","
	 * @param float $price          product-price
	 * @param int           $decimal                Decimals to round
	 * @return      string
	 */
	private function _floatToString($price, $decimals = 2)
	{
		return number_format((float) $price, $decimals, ',', '.');
	}

}

?>